package com.xqboss.apps.service.consumer;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xqboss.apps.constant.RedisKey;
import com.xqboss.apps.domain.box.Box;
import com.xqboss.apps.domain.marketing.MarketingAirdrop;
import com.xqboss.apps.domain.marketing.MarketingAirdropRecord;
import com.xqboss.apps.domain.member.SysUserNft;
import com.xqboss.apps.domain.nft.Nft;
import com.xqboss.apps.domain.nft.NftNumber;
import com.xqboss.apps.domain.order.OrderItem;
import com.xqboss.apps.domain.user.UserBox;
import com.xqboss.apps.dto.consumer.ConsumerRecycleQueryDto;
import com.xqboss.apps.dto.consumer.ConsumerRecycleSaveDto;
import com.xqboss.apps.enums.marketing.AirdropStatusEnum;
import com.xqboss.apps.enums.nft.NftDispatchSourceEnum;
import com.xqboss.apps.enums.nft.NftTypeEnum;
import com.xqboss.apps.enums.nft.UserNftStatusEnum;
import com.xqboss.apps.enums.user.UserNftSourceTypeEnum;
import com.xqboss.apps.service.box.BoxService;
import com.xqboss.apps.service.marketing.AirdropRecordService;
import com.xqboss.apps.service.marketing.AirdropService;
import com.xqboss.apps.service.nft.NftNumberService;
import com.xqboss.apps.service.nft.NftService;
import com.xqboss.apps.service.user.SysUserNftService;
import com.xqboss.apps.service.user.UserBoxService;
import com.xqboss.apps.vo.consumer.ConsumerRecycleVo;
import com.xqboss.common.core.domain.PageList;
import com.xqboss.common.core.redis.RedisCache;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.SecurityUtils;
import com.xqboss.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.domain.consumer.ConsumerRecycle;
import com.xqboss.apps.mapper.consumer.ConsumerRecycleMapper;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 回收空投(ConsumerRecycle)表服务实现类
 *
 * @author makejava
 * @since 2024-02-22 10:50:36
 */
@Service
public class ConsumerRecycleService extends ServiceImpl<ConsumerRecycleMapper, ConsumerRecycle> {

    @Autowired
    private SysUserNftService userNftService;

    @Autowired
    protected UserBoxService userBoxService;

    @Autowired
    private NftNumberService nftNumberService;

    @Autowired
    private BoxService boxService;

    @Autowired
    private NftService nftService;

    @Autowired
    private AirdropService airdropService;

    @Autowired
    private AirdropRecordService airdropRecordService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ISysUserService userService;


    /**
     * 分页列表
     * @param param
     * @return
     */
    public PageList<ConsumerRecycleVo> pageList(ConsumerRecycleQueryDto param) {
        PageList<ConsumerRecycleVo> pageList = new PageList<>();
        Page<ConsumerRecycle> page = new Page<>(param.getPageNum(), param.getPageSize());
        page = this.lambdaQuery()
                .eq(param.getFromUserId() != null, ConsumerRecycle::getFromUserId, param.getFromUserId())
                .eq(param.getToUserId() != null, ConsumerRecycle::getToUserId, param.getToUserId())
                .orderByDesc(ConsumerRecycle::getId)
                .page(page);
        pageList.setList(BeanUtil.copyToList(page.getRecords(), ConsumerRecycleVo.class));
        pageList.setTotal(page.getTotal());
        return pageList;
    }

    /**
     * 验证并保存
     * @param param
     */
    @Transactional
    public void verifyAndSave(ConsumerRecycleSaveDto param) {
        // 验证用户id是否存在
        if (param.getToUserId().equals(param.getFromUserId())) {
            throw new ServiceException("回收用户不能是空投用户");
        } else if (userService.selectUserById(param.getToUserId()) == null) {
            throw new ServiceException("空投用户id不存在");
        } else if (userService.selectUserById(param.getFromUserId()) == null) {
            throw new ServiceException("回收用户id不存在");
        }
        MarketingAirdrop airdrop = new MarketingAirdrop();
        List<SysUserNft> nftList = new ArrayList<>();
        Long airdropId = IdUtil.getSnowflakeNextId();
        Long airdropRecordId = IdUtil.getSnowflakeNextId();
        if (param.getType() == NftTypeEnum.BOX) {
            Box box = boxService.getById(param.getSourceId());
            if (box == null) {
                throw new ServiceException("宝盒不存在");
            }
            // 判断是否足够
            UserBox userBox = userBoxService.getUserBoxByBoxId(param.getFromUserId(), param.getSourceId());
            if (userBox.getQuantity() < param.getNum()) {
                throw new ServiceException("宝盒数量不足");
            }
            userBoxService.moveUserBoxToUser(userBox.getId(), param.getFromUserId(), param.getToUserId(), param.getNum());

            airdrop.setAirdropName(box.getName());
            airdrop.setAirdropImg(box.getHeadimg());
            airdrop.setPublishName(box.getPublishName());
        } else if (param.getType() == NftTypeEnum.EQUIPMENT || param.getType() == NftTypeEnum.NORMAL) {
            // 判断是否足够
            Long nftNumberId = null;
            if (StrUtil.isNotBlank(param.getNftNumberStr())) {
                NftNumber nftNumber = nftNumberService.lambdaQuery().eq(NftNumber::getNumberValueStr, param.getNftNumberStr()).one();
                if (nftNumber == null) {
                    throw new ServiceException("藏品或装备不存在");
                }
                nftNumberId = nftNumber.getId();
                param.setNum(1);
                param.setSourceId(nftNumber.getNftId());
            }
            // 验证nft是否存在
            Nft nft = nftService.getById(param.getSourceId());
            if (nft == null) {
                throw new ServiceException("藏品或装备不存在");
            }
            nftList = userNftService.lambdaQuery()
                    .eq(SysUserNft::getUserId, param.getFromUserId())
                    .eq(SysUserNft::getNftId, param.getSourceId())
                    .eq(SysUserNft::getNftStatus, UserNftStatusEnum.NORMAL)
                    .eq(nftNumberId != null, SysUserNft::getNftNumberId, nftNumberId)
                    .last("limit " + param.getNum())
                    .list();
            if (nftList.size() < param.getNum()) {
                throw new ServiceException("藏品或装备数量不足");
            }
            // 设置nftNumberStr
            param.setNftNumberStr(nftNumberService.lambdaQuery()
                    .select(NftNumber::getNumberValueStr)
                    .in(NftNumber::getId, nftList.stream().map(SysUserNft::getNftNumberId).collect(Collectors.toList()))
                    .list()
                    .stream()
                    .map(NftNumber::getNumberValueStr).collect(Collectors.joining(","))
            );
            for (SysUserNft t : nftList) {
                userNftService.moveUserNftToUser(t.getId(), param.getFromUserId(), param.getToUserId(), airdropRecordId, UserNftSourceTypeEnum.AIRDROP, NftDispatchSourceEnum.AIRDROP, null);
            }
            airdrop.setAirdropName(nft.getTitle());
            airdrop.setAirdropImg(nft.getMainImg());
            airdrop.setPublishName(nft.getPublishName());
        } else {
            throw new ServiceException("暂不支持的类型");
        }
        // 添加空投记录
        airdrop.setId(airdropId);
        airdrop.setSourceId(param.getSourceId());
        airdrop.setAirdropType(param.getType());
        airdrop.setReason(param.getToReason());
        airdrop.setAirdropStatus(AirdropStatusEnum.COMPLETE);
        airdrop.setUserSize(1);
        airdrop.setAirdropTime(LocalDateTime.now());
        airdrop.setCreateUserId(SecurityUtils.getUserId());
        airdrop.setCreateUserName(SecurityUtils.getUsername());
        airdrop.setQuantity(param.getNum());
        airdropService.save(airdrop);

        MarketingAirdropRecord record = new MarketingAirdropRecord();
        record.setId(airdropRecordId);
        record.setUserId(param.getToUserId());
        record.setAirdropId(airdrop.getId());
        record.setQuantity(param.getNum());
        record.setAirdropStatus(AirdropStatusEnum.COMPLETE);
        airdropRecordService.save(record);
        // 存未读缓存
        redisCache.increment(RedisKey.KEY_USER_UNREAD_GIFT + param.getToUserId());

        ConsumerRecycle entity = BeanUtil.copyProperties(param, ConsumerRecycle.class);
        this.save(entity);
    }
}
